#ifndef xpack_test_utils_unique_array
#define xpack_test_utils_unique_array
#pragma push_macro("xuser")
#undef  xuser
#define xuser mixc::test_utils_unique_array::inc
#include"test/helper.hpp" // 需要放第一
#include"utils/memory.hpp"
#include"utils/unique_array.hpp"
#pragma pop_macro("xuser")

namespace mixc::test_utils_unique_array{
    xtest("unique_array") {
        using namespace inc;
        using nlrd              = helper::nlrd_counter;
        using ua_t              = unique_array<nlrd>;


        auto length             = ::length(16);
        auto mem                = new nlrd[length];
        nlrd::reset_counter();

        // 测试不析构，不释放
        {
            ua_t test(mem, length, not need_destruction, not need_free);
        }

        xassert_nlrd(0, 0, 0, 0);
        delete[] mem;
        nlrd::reset_counter();




        // 测试不析构，但释放 + move 语义
        auto used_bytes         = inc::memory::used_bytes();
        {
            ua_t outside;
            {
                mem             = inc::memory::alloc<nlrd>(xsizeof(nlrd) * length);
                outside         = ua_t(mem, length, not need_destruction, need_free);
            }

            xassert_nlrd(0, 0, 0, 0);
            xassert_lt(used_bytes, inc::memory::used_bytes());
        }

        xassert_nlrd(0, 0, 0, 0);
        xassert_eq(used_bytes, inc::memory::used_bytes());



        // 测试析构，但不释放
        used_bytes              = inc::memory::used_bytes();
        {
            mem                 = inc::memory::alloc<nlrd>(xsizeof(nlrd) * length);
            ua_t(mem, length, need_destruction, not need_free);
        }

        xassert_nlrd(0, 0, 0, length);
        xassert_lt(used_bytes, inc::memory::used_bytes());
        inc::memory::free(mem, xsizeof(nlrd) * length);




        // 测试析构，并释放
        used_bytes              = inc::memory::used_bytes();
        {
            mem                 = inc::memory::alloc<nlrd>(xsizeof(nlrd) * length);
            ua_t foo(mem, length, need_destruction, need_free);
        }

        xassert_nlrd(0, 0, 0, length);
        xassert_eq(used_bytes, inc::memory::used_bytes());



        // 测试 operator[] 接口
        {
            mem                 = inc::memory::alloc<nlrd>(xsizeof(nlrd) * length);

            for(uxx i = 0; i < length; i++){
                mem[i].value    = i;
            }

            ua_t foo(mem, length, not need_destruction, need_free);

            foo.foreach([&](uxx i, nlrd & item){
                xassert_eq(i, item.value);
            });

            for(uxx i = 0; i < foo->length; i++){
                xassert_eq(foo[i].value, i);
            }
        }




        // 测试 operator=(nullptr)，== nullptr != nullptr
        used_bytes              = inc::memory::used_bytes();
        {
            mem                 = inc::memory::alloc<nlrd>(xsizeof(nlrd) * length);
            ua_t foo(mem, length, need_destruction, need_free);
            xassert_nlrd(0, 0, 0, 0);
            xassert(foo != nullptr);
            foo                 = nullptr;
            xassert_nlrd(0, 0, 0, length);
            xassert(foo == nullptr);
            xassert_eq(used_bytes, inc::memory::used_bytes());

            ua_t bar;
            xassert(bar == nullptr);
        }

        xassert_nlrd(0, 0, 0, 0);
        xassert_eq(used_bytes, inc::memory::used_bytes());



        // 测试 lend 接口
        {
            mem                 = inc::memory::alloc<nlrd>(xsizeof(nlrd) * length);

            ua_t foo(mem, length, not need_destruction, need_free);
            ua_t bar;
            xassert_nlrd(0, 0, 0, 0);
            xassert_ne(foo.lend(), nullptr);
            xassert_eq(bar.lend(), nullptr);
        }

        xassert_nlrd(0, 0, 0, 0);

        // 都没有元素，move 构造
        {
            ua_t test0;
            ua_t test1 = test0.hand_over();
            xassert_nlrd(0, 0, 0, 0);
        }

        xassert_nlrd(0, 0, 0, 0);

        // 都没有元素，move 赋值
        {
            ua_t test0;
            ua_t test1;
            test1               = test0.hand_over();
            xassert_nlrd(0, 0, 0, 0);
        }

        xassert_nlrd(0, 0, 0, 0);


        // test0 有元素，构造转移给 test1
        {
            mem                 = inc::memory::alloc<nlrd>(xsizeof(nlrd) * length);
            ua_t test0(mem, length, need_destruction, need_free);
            ua_t test1          = test0.hand_over();
            xassert_nlrd(0, 0, 0, 0);
            test0               = nullptr;
            xassert_nlrd(0, 0, 0, 0);
            test1               = nullptr;
            xassert_nlrd(0, 0, 0, length);
        }

        xassert_nlrd(0, 0, 0, 0);

        // test0 有元素，赋值转移给 test1
        {
            mem                 = inc::memory::alloc<nlrd>(xsizeof(nlrd) * length);
            ua_t test0(mem, length, need_destruction, need_free);
            ua_t test1;
            xassert_nlrd(0, 0, 0, 0);
            test1               = test0.hand_over();
            xassert_nlrd(0, 0, 0, 0);
            test0               = nullptr;
            xassert_nlrd(0, 0, 0, 0);
        }

        xassert_nlrd(0, 0, 0, length);
    };
}

#endif
